#include "MultiThreadSolver.h"
#include <QtConcurrent>
#include <iostream>
#include "qfuture.h"

MultiThreadSolver::MultiThreadSolver(int n) {
  lastRes = nullptr;
  m_state = EightQueenSolver::FREE;
  setN(n);
}

void MultiThreadSolver::solve() {
  resNum = 0;
  m_state = EightQueenSolver::RUNNING;
  mstimer.start();

  // 只需计算N/2或N/2+1列，然后根据对称变换求得结果
  int taskSize = m_n / 2 + (m_n % 2 == 1 ? 1 : 0);

  QList<QFuture<int>> futureList;
  for (int i = 0; i < taskSize; ++i) {
      // 开启一个线程，计算皇后在第i列的解数
    futureList.append(QtConcurrent::run(&MultiThreadSolver::putQueenAtRow, this,
                                        chessList[i],1));
  }
  // 将各线程结果相加
  for (int i = 0; i < (taskSize - (m_n % 2 == 1 ? 1 : 0)); ++i) {
    resNum += futureList.at(i).result();
  }
  // 计算对称变换总结果
  resNum *= 2;
  if (m_n % 2 == 1)
    resNum += futureList.at(m_n / 2).result();

  time = (double)mstimer.nsecsElapsed() / (double)1000000000;
  if(m_state==EightQueenSolver::STOPPED)
      emit stopped();
  else
    emit finished();
  m_state = EightQueenSolver::FREE;
}

void MultiThreadSolver::setN(int n) {
  qDeleteAll(chessList);
  chessList.clear();
  if (lastRes)
    delete[] lastRes;
  resNum = 0;

  m_n = n;
  lastRes = new int[n];
  for (int i = 0; i < n; ++i) {
      lastRes[i]=-1;
  }

  for (int i = 0; i < m_n; ++i) {
    int* chess = new int[m_n];
    // chess[row]=col 表示皇后在第row行第col列
    chess[0] = i;
    chessList.append(chess);
  }
  m_state = EightQueenSolver::FREE;
}

void MultiThreadSolver::stopSolve() {
  m_state = EightQueenSolver::STOPPED;
}

int MultiThreadSolver::putQueenAtRow(Board1D chess, int row) {
  if (m_state == EightQueenSolver::STOPPED)
    return 0;
  if (row == m_n) {
    memcpy(lastRes, chess, m_n * sizeof(int));
    emit oneResult();
    return 1;
  }

  int* chessTemp = new int[m_n];
  memcpy(chessTemp, chess, m_n * sizeof(int));
  int sum = 0;

  for (int i = 0; i < m_n; ++i) {
    chessTemp[row] = i;
    if (isSafe(chessTemp, row, i)) {
      sum += putQueenAtRow(chessTemp, row + 1);
    }
  }
  delete[] chessTemp;
  return sum;
}

bool MultiThreadSolver::isSafe(Board1D chess, int row, int col) {
  int step = 1;
  for (int i = row - 1; i >= 0; i--) {
    if (chess[i] == col)  //中上
      return false;
    if (chess[i] == col - step)  //左上
      return false;
    if (chess[i] == col + step)  //右上
      return false;

    step++;
  }
  return true;
}
